package Gr

import (
	"db2s/ETL"
	"db2s/global"
	"db2s/go-log/log"
	"db2s/parDef"
	"db2s/ref"
	"errors"
	"fmt"
	"reflect"
	"strings"
)

func newTimeTypeToFunc(colMap, columnName, asColumn string) (r string) {
	switch colMap {
	case "year-month-day":
		r = fmt.Sprintf("date_format(%v,'%%Y-%%m-%%d') as `%v`", columnName, asColumn)
	case "hour:minute:second":
		r = fmt.Sprintf("date_format(%v,'%%H:%%i:%%s') as `%v`", columnName, asColumn)
	case "year-month-day hour:minute:second":
		r = fmt.Sprintf("date_format(%v,'%%Y-%%m-%%d %%H:%%i:%%s') as `%v`", columnName, asColumn)
	case "hour:minute:second.milli(1)", "hour:minute:second.milli(2)", "hour:minute:second.milli(3)", "hour:minute:second.micro(1)", "hour:minute:second.micro(2)", "hour:minute:second.micro(3)", "hour:minute:second.nano(1)", "hour:minute:second.nano(2)", "hour:minute:second.nano(3)":
		r = fmt.Sprintf("date_format(%v,'%%H:%%i:%%s.%%f') as `%v`", columnName, asColumn)
	case "year":
		r = fmt.Sprintf("date_format(%v,'%%Y') as `%v`", columnName, asColumn)
	case "year-month-day hour:minute:second.milli(1)", "year-month-day hour:minute:second.milli(2)", "year-month-day hour:minute:second.milli(3)", "year-month-day hour:minute:second.micro(1)", "year-month-day hour:minute:second.micro(2)", "year-month-day hour:minute:second.micro(3)", "year-month-day hour:minute:second.nano(1)", "year-month-day hour:minute:second.nano(2)", "year-month-day hour:minute:second.nano(3)":
		r = fmt.Sprintf("date_format(%v,'%%Y-%%m-%%d %%H:%%i:%%s.%%f') as `%v`", columnName, asColumn)
	default:
		r = fmt.Sprintf("date_format(%v,'%%Y-%%m-%%d %%H:%%i:%%s') as `%v`", columnName, asColumn)
	}
	return
}
func newFloatTypeToFunc(precision, scale int64, columnName, asColumn string) (r string) {
	var decimal []string
	if precision > 0 {
		decimal = append(decimal, fmt.Sprintf("%v", precision))
	}
	if scale > 0 {
		decimal = append(decimal, fmt.Sprintf("%v", scale))
	}
	if len(decimal) > 0 {
		r = fmt.Sprintf("CAST(%v AS DECIMAL(%v)) as `%v`", columnName, strings.Join(decimal, ","), asColumn)
	} else {
		r = fmt.Sprintf("%v as `%v`", columnName, asColumn)
	}
	return
}
func newDecimalTypeToFunc(columnName, asColumn string) (r string) {
	r = fmt.Sprintf("0+CAST(%v as char)  as `%v`", columnName, asColumn)
	return
}
func newGisTypeToFunc(colSubType string, columnName, asColumn string) (r string) {
	switch strings.ToUpper(colSubType) {
	case "POINT":
	case "MULTIPOINT":
	case "LINESTRING":
	case "MULTILINESTRING":
	case "POLYGON":
	case "MULTIPOLYGON":
	case "GEOMETRY":
	case "GEOMETRYCOLLECTION":
	}
	return fmt.Sprintf("concat(left(st_asgeojson(%v),length(st_asgeojson(%v)) -1 ),', \"RID\":',st_srid(geom),'}') as `%v`", columnName, columnName, asColumn)
}
func NewSpecialTypeToFunc(LockCol parDef.Encryption, colMap parDef.ColMetaMapS) (r string) {
	asColumn := fmt.Sprintf("C%v", colMap.ColumnSeq)
	var unlockFunc string
	for _, v := range LockCol.Column {
		if strings.EqualFold(v, colMap.ColumnName) && len(LockCol.UnlockFunc) > 0 {
			unlockFunc = fmt.Sprintf("%v.%v(`%v`)", LockCol.Schema, LockCol.UnlockFunc, colMap.ColumnName)
			break
		}
	}
	if len(unlockFunc) == 0 {
		unlockFunc = fmt.Sprintf("`%v`", colMap.ColumnName)
	}
	switch colMap.TypeBelong {
	case "time", "timestamp":
		return newTimeTypeToFunc(colMap.Type.ColTypeMap, unlockFunc, asColumn)
	case "float", "double":
		return newFloatTypeToFunc(colMap.Type.Precision, colMap.Type.Scale, unlockFunc, asColumn)
	case "decimal":
		return newDecimalTypeToFunc(unlockFunc, asColumn)
	case "gis":
		return newGisTypeToFunc(colMap.Type.ColTypeMap, unlockFunc, asColumn)
	default:
		return fmt.Sprintf("%v as `%v`", unlockFunc, asColumn)
	}
}
func newTimeValueToFunc(colMap, value string) (r string) {
	switch colMap {
	case "year-month-day":
		r = fmt.Sprintf("DATE_FORMAT(%s,'%%Y-%%m-%%d')", value)
	case "hour:minute:second":
		r = fmt.Sprintf("DATE_FORMAT(%s,'%%H:%%i:%%s')", value)
	case "year-month-day hour:minute:second":
		r = fmt.Sprintf("DATE_FORMAT(%s,'%%Y-%%m-%%d %%H:%%i:%%s')", value)
	default:
		r = fmt.Sprintf("DATE_FORMAT(%s,'%%Y-%%m-%%d %%H:%%i:%%s')", value)
	}
	return
}

// NewSpecialCharValueToFunc 根据列的数据类型，将字符串值继续函数转换
func NewSpecialCharValueToFunc(colMap parDef.ColMetaMapS, value string) (newValue string) {
	newValue = strings.ReplaceAll(value, "'", "\\'")
	switch colMap.TypeBelong {
	case "time":
		return newTimeValueToFunc(colMap.Type.ColTypeMap, newValue)
	default:
		newValue = value
		return
	}
}

func (rows RowsF) Prefix(parameter parDef.Parameter) (result global.Return, err error) {
	var (
		tableName, ignoreStr string
		insertColumn         []string
	)
	//if s.Insert.Prefix.Ignore {
	//ignoreStr = "IGNORE" //timetimp类型 Incorrect datetime value: '2024-09-26 11:27:28 +0800 08:00' for column
	//}
	if result, err = rows.InsertAllCol(parameter); err != nil {
		err = ref.ErrAddPrintf("GreatDB.Prefix", err)
		return
	}
	switch result.Result.(type) {
	case []string:
		insertColumn = result.Result.([]string)
	default:
		err = ref.ErrAddPrintf("GreatDB.Prefix", errors.New(fmt.Sprintf("type not match. curry type is %v", reflect.TypeOf(result.Result))))
	}
	tableName = fmt.Sprintf(" `%v`.`%v` ", parameter.Object.Schema, parameter.Object.Table)
	result.Result = fmt.Sprintf("%s ", fmt.Sprintf("INSERT %v INTO %v (`%s`) VALUES", ignoreStr, tableName, strings.Join(insertColumn, "`,`")))
	if parameter.Object.LobLogo {
		var s1 []string
		for i := 0; i < len(insertColumn); i++ {
			s1 = append(s1, "?")
		}
		result.Result = fmt.Sprintf("INSERT INTO %v (`%s`) VALUES (%s)", tableName, strings.Join(insertColumn, "`,`"), strings.Join(s1, ","))
	}
	return
}

func (rows RowsF) writeFileDML(parameter parDef.Parameter) (result global.Return, err error) {
	if parameter.ExecDML.FilePoint == nil {
		return
	}
	if err = parameter.ExecDML.FilePoint.Write("", parameter.ExecDML.Sql); err != nil {
		return
	}
	return
}

func (rows RowsF) connExecDML(parameter parDef.Parameter) (result global.Return, err error) {
	//var event = "[ExecDDL]"
	//if result.TimeOut, result.Result, err = newExecUpdateSql(ExecSqlInputS{
	//	Ss:           parameter,
	//	Event:        event,
	//	UpdateSqlStr: []string{parameter.ExecDML.Sql},
	//}); err != nil {
	//	return
	//}
	return
}

func (rows RowsF) ExecDML(parameter parDef.Parameter) (result global.Return, err error) {
	switch parameter.Options.RepairMethod {
	case "table":
		return rows.writeFileDML(parameter)
	case "file":
		return rows.connExecDML(parameter)
	default:
		err = errors.New(fmt.Sprintf("The repair method was not matched"))
	}
	return
}
func (rows RowsF) SelectIdxCol(parameter parDef.Parameter) (result global.Return, err error) {
	return
}
func (rows RowsF) SelectAllCol(parameter parDef.Parameter) (result global.Return, err error) {
	var columnName, asColumnName []string
	for _, v := range parameter.Object.Column {
		asColumnName = append(asColumnName, fmt.Sprintf("C%v", v.ColumnSeq))
		columnName = append(columnName, NewSpecialTypeToFunc(parameter.Object.LockCol, v))
	}
	result.Result = columnName
	return
}
func (rows RowsF) InsertAllCol(parameter parDef.Parameter) (result global.Return, err error) {
	return
}
func (rows RowsF) StringValueCompare(parameter parDef.Parameter) (result global.Return, err error) {
	return
}
func (rows RowsF) IndexPart(parameter parDef.Parameter) (result global.Return, err error) {
	return
}
func (rows RowsF) SelectRowsSql(parameter parDef.Parameter) (result global.Return, err error) {
	return
}
func (rows RowsF) ReadData(parameter parDef.Parameter) (result global.Return, err error) {
	var event = "[ReadData]"
	var execSql []string
	defer func() {
		if r := recover(); r != nil {
			err = errors.New(fmt.Sprintf("%v defer recover An exception was captured. abnormal is %v ", event, r))
		}
	}()
	if parameter.Meta == nil {
		return
	}
	switch parameter.Meta.(type) {
	case string:
		execSql = append(execSql, parameter.Meta.(string))
	case []string:
		execSql = parameter.Meta.([]string)
	default:
		err = ref.ErrAddPrintf("GreatDB.ReadData", errors.New(fmt.Sprintf("type not matched. curry type %v", reflect.TypeOf(parameter.Meta))))
		return
	}
	if result, err = forExecQuerySql(event, parameter, ETL.GarthStringPointGarth, execSql); err != nil {
		err = ref.ErrAddPrintf("GreatDB.ReadData", err)
		return
	}
	return
}
func (rows RowsF) ReadMiss(parameter parDef.Parameter) (result global.Return, err error) {
	var (
		event   = "[MySQL.ReadMiss]"
		res     global.Return
		execSql []string
	)
	defer func() {
		if r := recover(); r != nil {
			err = errors.New(fmt.Sprintf("%v defer recover An exception was captured. abnormal is %v ", event, r))
		}
	}()
	if res, err = rows.SelectAllCol(parameter); err != nil {
		err = ref.ErrAddPrintf(event, err)
		return
	}
	if res.Result == nil {
		log.MainLog().Warn(event, "no data to read")
		return
	}
	execSql = append(execSql, fmt.Sprintf("select %v \n"+
		"from %v "+
		"where 1= 1 %v \n",
		strings.Join(res.Result.([]string), ","),
		tableObject(parameter.Object.Schema, parameter.Object.Table, parameter.Object.Partition),
		rowsLimitC(parameter.Options.RowsLimit)))
	log.MainLog().Debug(event, fmt.Sprintf(" sql is %v", execSql))
	if result, err = forExecQuerySql(event, parameter, ETL.FlowAny, execSql); err != nil {
		err = ref.ErrAddPrintf(event, err)
		return
	}
	return
}
func (rows RowsF) InsertSql(parameter parDef.Parameter) (result global.Return, err error) {
	return
}
func (rows RowsF) Insert(parameter parDef.Parameter) (result global.Return, err error) {
	return
}
